package cn.b.sky.mes.hr.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import cn.b.sky.mes.hr.model.PersonnelTypeAssign;
import cn.b.sky.mes.hr.model.Shifting;
import cn.b.sky.mes.hr.model.ShiftingPermission;
import cn.b.sky.mes.hr.model.condition.ShiftingCondition;
import cn.b.sky.mes.hr.service.PersonnelTypeAssignService;
import cn.b.sky.mes.hr.service.ShiftingPermissionService;
import cn.b.sky.mes.hr.service.ShiftingService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.b.sky.mes.cm.model.WorkDayPeriod;
import cn.b.sky.mes.cm.service.WorkDayTypeService;
import cn.b.sky.common.model.BatchJobReport;
import cn.b.sky.common.model.DWZResult;
import cn.b.sky.user.SecurityContextUtil;
import cn.b.sky.user.controller.SecurityController;

import com.alibaba.fastjson.JSON;

@Controller
@RequestMapping(value = "/shifting/*")
public class ShiftingController extends SecurityController {
  /**
   * 列表界面
   */
  private static final String SHIFTING_LIST_PAGE = "hr/shifting/shifting_list";

  /**
   * 新增界面 
   */
  private static final String SHIFTING_ADD_PAGE = "hr/shifting/shifting_add";

  /**
   * 批量新增界面
   */
  private static final String SHIFTING_BATCH_ADD_PAGE = "hr/shifting/shifting_batch_add";

  /**
   * 编辑界面
   */
  private static final String SHIFTING_EDIT_PAGE = "hr/shifting/shifting_edit";

  /**
   * 详情界面
   */
  private static final String SHIFTING_VIEW_PAGE = "hr/shifting/shifting_view";

  /**
   * 复制界面
   */
  private static final String SHIFTING_COPY_PAGE = "hr/shifting/shifting_copy";

  /**
   * 一天（毫秒数）
   */
  private static final int PER_DAY = 24 * 60 * 60 * 1000;

  private static final String FIRST_DATETIME = "firstDateTime";

  private static final String LAST_DATETIME = "lastDateTime";

  @Autowired
  private ShiftingPermissionService shiftingPermissionService;

  @Autowired
  private ShiftingService shiftingService;

  @Autowired
  WorkDayTypeService workDayTypeService;

  @Autowired
  PersonnelTypeAssignService personnelTypeAssignService;

  /**
   * 
   * <strong>Title : shiftingListPage<br>
   * </strong> <strong>Description : </strong>排班列表页面映射<br>
   * <strong>Create on : 2016年3月25日 上午10:29:10<br>
   * </strong>
   * <p>
   * 
   * @param navTabId
   * @param model
   * @return String
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  @RequestMapping("shifting_list")
  public String shiftingListPage(String navTabId, Model model) {
    model.addAttribute(NAVTABID, navTabId);
    bindShiftingPermissions(navTabId, model);
    return SHIFTING_LIST_PAGE;
  }

  /**
   * 
   * <strong>Title : addShiftingPage<br>
   * </strong> <strong>Description : </strong>新增排班页面映射<br>
   * <strong>Create on : 2016年3月25日 上午10:29:29<br>
   * </strong>
   * <p>
   * 
   * @param navTabId
   * @param model
   * @return String
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  @RequestMapping("addShifting")
  public String addShiftingPage(String navTabId, Model model) {
    bindShiftingPermissions(navTabId, model);
    return SHIFTING_ADD_PAGE;
  }

  @RequestMapping("batchAddShifting")
  public String batchAddShiftingPage(String navTabId, Model model) {
    bindShiftingPermissions(navTabId, model);
    return SHIFTING_BATCH_ADD_PAGE;
  }

  @RequestMapping("modifyShifting")
  public String modifyShiftingPage(String navTabId, Model model, Long id) {
    Shifting shifting = shiftingService.getShiftingById(id);
    bindShiftingPermissions(navTabId, model, shifting, 0);
    model.addAttribute("shifting", shifting);
    List<PersonnelTypeAssign> ptas = personnelTypeAssignService.getPersonnelTypeAssignsByPersonnel(getSiteCode(),
        shifting.getPersonnelCode());
    model.addAttribute("ptas", ptas);
    return SHIFTING_EDIT_PAGE;
  }

  @RequestMapping("viewShifting")
  public String viewShiftingPage(String navTabId, Model model, Long id) {
    Shifting shifting = shiftingService.getShiftingById(id);
    bindShiftingPermissions(navTabId, model);
    model.addAttribute("shifting", shifting);
    return SHIFTING_VIEW_PAGE;
  }

  @RequestMapping("copyShifting")
  public String copyShiftingPage(String navTabId, Model model) {
    bindShiftingPermissions(navTabId, model);
    return SHIFTING_COPY_PAGE;
  }

  @RequestMapping("getShiftingsByWorkcenterAndDate")
  @ResponseBody
  public List<Shifting> getShiftingsByWorkcenterAndDate(String workcenterCode, String theDate) {
    return shiftingService.getShiftingsByWorkcenterAndDate(getSiteCode(), workcenterCode, theDate);
  }

  private void bindShiftingPermissions(String navTabId, Model model) {
    bindShiftingPermissions(navTabId, model, null, null);
  }

  /**
   * 
   * <strong>Title : bindWorcenterTree<br>
   * </strong> <strong>Description : </strong>绑定工作中心的tree<br>
   * <strong>Create on : 2016年3月25日 上午10:29:52<br>
   * </strong>
   * <p>
   * 
   * @param navTabId
   * @param model
   *            void
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  private void bindShiftingPermissions(String navTabId, Model model, Shifting edit, Integer lockFlag) {
    List<ShiftingPermission> permissions = shiftingPermissionService.getPermissionsByUser(getSiteCode(),
        SecurityContextUtil.getCurrentUserName(), lockFlag);
    boolean isIncluded = false;
    if (null != edit) {
      for (ShiftingPermission sp : permissions) {
        if (sp.getWorkcenterCode().equals(edit.getShiftingWorkcenterCode())) {
          isIncluded = true;
          break;
        }
      }
      if (!isIncluded) {
        ShiftingPermission permission = new ShiftingPermission();
        permission.setWorkcenterCode(edit.getShiftingWorkcenterCode());
        permission.setWorkcenterText(edit.getShiftingWorkcenterText());
        permissions.add(permission);
      }
    }
    model.addAttribute(NAVTABID, navTabId);
    model.addAttribute("permissions", permissions);
  }

  /**
   * 
   * <strong>Title : getShiftingList<br>
   * </strong> <strong>Description : </strong>获取排班数据列表<br>
   * <strong>Create on : 2016年3月25日 上午10:30:08<br>
   * </strong>
   * <p>
   * 
   * @param condition
   * @return DWZResult
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  @RequestMapping("getShiftingList")
  @ResponseBody
  public DWZResult getShiftingList(ShiftingCondition condition) {
    condition.setSiteCode(getSiteCode());
    List<ShiftingPermission> permissions = shiftingPermissionService.getPermissionsByUser(this.getSiteCode(),
        SecurityContextUtil.getCurrentUserName(), null);
    List<Shifting> list = new ArrayList<Shifting>();
    int count = 0;
    if (!permissions.isEmpty()) {
      condition.setPermission(permissions);
      list = shiftingService.getShiftingsListByCondition(condition);
      count = shiftingService.getShiftingsCountByCondition(condition);
    }
    condition.setTotalCount(count);
    condition.setData(list);
    return ajaxDone(condition);
  }

  @RequestMapping("validateShifting")
  @ResponseBody
  public Map<String, Object> validateShifting(String navTabId, Shifting shifting) {
    Map<String, Object> map = new HashMap<String, Object>();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date theDate = shifting.getTheDate();
    Date firstStartTime = null;
    Date lastEndTime = null;
    Long id = shifting.getId();
    if (null == id) {
      id = 0L;
    }
    List<Shifting> shiftings = shiftingService.getShiftingByPersonnelAndPeriod(getSiteCode(),
        shifting.getPersonnelCode(), sdf.format(theDate), id);
    List<Shifting> overlappingShiftings = new LinkedList<Shifting>();
    List<Shifting> shiftingsForDay = new LinkedList<Shifting>();
    for (Shifting sf : shiftings) {
      if (sf.getTheDate().compareTo(theDate) == 0) {
        if (null == firstStartTime) {
          firstStartTime = sf.getStartDateTime();
        }
        if (null == lastEndTime || lastEndTime.compareTo(sf.getEndDateTime()) < 0) {
          lastEndTime = sf.getEndDateTime();
        }
        shiftingsForDay.add(sf);
      }
      if (validateShiftingOverlapping(shifting, sf)) {
        overlappingShiftings.add(sf);
      }
    }
    // 当前日期的排班数据
    map.put("shiftings", shiftingsForDay);
    // 与当前排班时间范围冲突的排班数据
    map.put("overlappingShiftings", overlappingShiftings);
    // 当前日期第一个排班开始时间
    map.put("firstStartTime", firstStartTime);
    // 当前日期最后一个排班结束时间
    map.put("lastEndTime", lastEndTime);
    return map;
  }

  @RequestMapping("getShiftingListByPersonnelAndDate")
  @ResponseBody
  public List<Shifting> getShiftingListByPersonnelAndDate(String personnelCode, String theDate) {
    return shiftingService.getShiftingByPersonnelAndDate(getSiteCode(), personnelCode, theDate, 0L);
  }

  /**
   * 
   * <strong>Title : validateShiftingOverlap<br>
   * </strong> <strong>Description : </strong>判断两个排班的时间是否重叠<br>
   * <strong>Create on : 2016年3月29日 下午1:29:18<br>
   * </strong>
   * <p>
   * 
   * @param arg0
   * @param arg1
   * @return boolean
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  private boolean validateShiftingOverlapping(Shifting arg0, Shifting arg1) {
    boolean isOverlapping = true;
    // arg0的开始时间小于arg1的开始时间，且arg0的结束时间小于等于arg1的开始时间，则两个时间段不重叠
    if (arg0.getStartDateTime().compareTo(arg1.getStartDateTime()) < 0
        && arg0.getEndDateTime().compareTo(arg1.getStartDateTime()) <= 0) {
      isOverlapping = false;
    }
    // arg0的结束时间大于arg1的结束时间，且arg0的开始时间大于等于arg1的结束时间，则两个时间段不重叠
    if (arg0.getEndDateTime().compareTo(arg1.getEndDateTime()) > 0
        && arg0.getStartDateTime().compareTo(arg1.getEndDateTime()) >= 0) {
      isOverlapping = false;
    }
    return isOverlapping;
  }

  @RequestMapping("saveShifting")
  @ResponseBody
  public DWZResult saveShifting(String navTabId, Shifting shifting) {
    shifting.setSiteCode(getSiteCode());
    setCreateInfo(shifting);
    shiftingService.saveShifting(shifting, false);
    return dialogAjaxDone(getImeViewMessageI18n(null, "successfulOperation.M"), navTabId, null, null, shifting);
  }

  @RequestMapping("batchSaveShiftingList")
  @ResponseBody
  public DWZResult batchSaveShiftingList(String shiftings) {
    List<Shifting> shiftingList = JSON.parseArray(shiftings, Shifting.class);
    for (Shifting shifting : shiftingList) {
      shifting.setSiteCode(getSiteCode());
      setCreateInfo(shifting);
      shiftingService.saveShifting(shifting, false);
    }
    return ajaxDone(true);
  }

  @RequestMapping("validateShiftingList")
  @ResponseBody
  public DWZResult validateShiftingList(String shiftings, String theDate) {
    boolean isInvalid = false;
    List<Shifting> list = JSON.parseArray(shiftings, Shifting.class);
    Map<String, List<Shifting>> map = groupShiftingByPersonnel(list);
    for (String personnelCode : map.keySet()) {
      List<Shifting> formList = map.get(personnelCode);
      List<Shifting> listFromDb = shiftingService.getShiftingByPersonnelAndPeriod(getSiteCode(), personnelCode,
          theDate, 0L);
      Map<String, Object> validationMap = new HashMap<String, Object>();
      for (Shifting shifting : formList) {
        // 表单提交的人员的每条数据与数据库已经存在的数据进行校验
        isInvalid = batchValidateShifting(validationMap, theDate, shifting, listFromDb);
        if (isInvalid) {
          break;
        }
        // 校验通过后，则下一条数据还要和当前数据校验
        listFromDb.add(shifting);
      }
      if (isInvalid) {
        break;
      }
    }
    return ajaxDone(isInvalid);
  }

  /**
   * 
   * <strong>Title : groupShiftingByPersonnel<br>
   * </strong> <strong>Description : </strong>按人员对排班数据分组<br>
   * <strong>Create on : 2016年4月6日 下午2:48:11<br>
   * </strong>
   * <p>
   * 
   * @param list
   * @return Map<String,List<Shifting>>
   * @throws
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  private Map<String, List<Shifting>> groupShiftingByPersonnel(List<Shifting> list) {
    Map<String, List<Shifting>> map = new HashMap<String, List<Shifting>>();
    for (Shifting shifting : list) {
      if (!map.containsKey(shifting.getPersonnelCode())) {
        map.put(shifting.getPersonnelCode(), new ArrayList<Shifting>());
      }
      map.get(shifting.getPersonnelCode()).add(shifting);
    }
    return map;
  }

  /**
   * 
   * <strong>Title : batchValidateShifting<br></strong>
   * <strong>Description : </strong>校验当前日期里的排班时间是否冲突，排班时间段是否超过24小时<br> 
   * <strong>Create on : 2016年5月11日 下午1:16:07<br></strong>
   * <p>
   * @param validationMap 临时保存校验数据
   * @param theDate 校验时间跨度是否超过24小时的日期
   * @param source 被校验的shifting
   * @param shiftingList 相比较的shifting集合
   * @return
   * void
   * @throws 
   * @author dapeng.li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  private boolean batchValidateShifting(Map<String, Object> validationMap, String theDate, Shifting source,
      List<Shifting> shiftingList) {
    boolean isOverlapping = false;
    boolean isOverTime = false;
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date firstDateTime = getMinStart(source.getStartDateTime(), validationMap.get(FIRST_DATETIME));
    Date lastDateTime = getMaxEnd(source.getEndDateTime(), validationMap.get(LAST_DATETIME));
    for (Shifting target : shiftingList) {
      isOverlapping = validateShiftingOverlapping(source, target);
      // 只要有重叠跳出循环
      if (isOverlapping) {
        break;
      }
      if (sdf.format(target.getTheDate()).equals(theDate)) {
        firstDateTime = getMinStart(firstDateTime, target.getStartDateTime());
        lastDateTime = getMaxEnd(lastDateTime, target.getEndDateTime());
      }
      isOverTime = lastDateTime.getTime() - firstDateTime.getTime() > PER_DAY;
      // 只要有超时跳出循环
      if (isOverTime) {
        break;
      }
    }
    validationMap.put(FIRST_DATETIME, firstDateTime);
    validationMap.put(LAST_DATETIME, lastDateTime);
    return isOverlapping || isOverTime;
  }

  private Date getMinStart(Date source, Object target) {
    if (null != target && source.compareTo((Date) target) > 0) {
      return (Date) target;
    }
    return source;
  }

  private Date getMaxEnd(Date source, Object target) {
    if (null != target && source.compareTo((Date) target) < 0) {
      return (Date) target;
    }
    return source;
  }

  @RequestMapping("getLatestAnnangedDate")
  @ResponseBody
  public Date getLatestAnnangedDate(String workcenterCode) {
    return shiftingService.getLatestAnnangedDate(getSiteCode(), workcenterCode);
  }

  @RequestMapping("getOwnPermissions")
  @ResponseBody
  public List<ShiftingPermission> getOwnPermissions() {
    return shiftingPermissionService
        .getPermissionsByUser(getSiteCode(), SecurityContextUtil.getCurrentUserName(), null);
  }

  @RequestMapping("getWorkDayPeriods")
  @ResponseBody
  public List<WorkDayPeriod> getWorkDayPeriods(String workcenterCode, String date) {
    return workDayTypeService.selectWorkDayPeriodsByWorkcenterAndDate(getSiteCode(), workcenterCode, date);
  }

  @RequestMapping("deleteShiftings")
  @ResponseBody
  public DWZResult deleteShiftings(HttpServletRequest request, String navTabId, String ids) {
    String[] idArr = ids.split(",");
    List<BatchJobReport> reports = new LinkedList<BatchJobReport>();
    int failures = 0;
    for (String idStr : idArr) {
      if (!StringUtils.isEmpty(idStr)) {
        BatchJobReport jobReport = shiftingService.deleteShiftingById(Long.valueOf(idStr), false);
        if (!jobReport.isSuccess()) {
          reports.add(jobReport);
          failures += 1;
        }
      }
    }
    if (failures > 0) {
      return batchjobAjaxDone(request, reports);
    }
    return ajaxDone(true);
  }

  @RequestMapping("getPTAsByPersonnel")
  @ResponseBody
  public List<PersonnelTypeAssign> getPTAsByPersonnel(String personnelCode) {
    return personnelTypeAssignService.getPersonnelTypeAssignsByPersonnel(getSiteCode(), personnelCode);
  }
}